/**
 * websocket 管理
 * @author luguoxiang
 * @date 2024-06-19
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
import { onMounted, onUnmounted } from 'vue';
import { loadToken } from '@/soar';
import * as bus from '@/soar/hooks/bus';
import { baseURL } from '@/config/global';

/**
 * websocket 消息事件名称
 */
export const EVENT_NAME = '$ws:';

const state = {
  ws: null as any,
  timer: null as any,
  heartBeat: 0,
  /**
   * 启用
   */
  enabled: false,
  promises: null as any[] | null,
};

/**
 * 连接
 * @param resolve
 */
function connect(resolve: Function, reject: Function) {
  if (!state.enabled) {
    return;
  }
  if (state.ws) {
    resolve(state.ws);
  }
  loadToken().then(({ token }) => {
    // 打开连接
    const ws = new WebSocket(`ws${window.location.origin.substring(4)}${baseURL}/system/ws?token=${token}`);
    state.ws = ws;
    // 消息处理
    ws.onmessage = ({ data }) => {
      bus.emit(EVENT_NAME, data);
      const index = data.indexOf('::');
      if (index === -1) {
        return;
      }
      const topic = data.substring(0, index);
      data = data.substring(index + 2);
      bus.emit(EVENT_NAME + topic, data);
    };
    // 意外关闭重连
    ws.onclose = () => {
      if (state.enabled) {
        delete state.ws;
        setTimeout(() => connect(resolve, reject), 30_000);
      }
    };
    // 异常处理
    /* ws.onerror = () => {

    } */
    ws.onopen = () => {
      resolve(ws);
    };
    // 心跳处理
    /*  state.timer = setInterval(() => {
        if (state.ws) {
          state.heartBeat = Math.random();
          send('HeartBeat', state.heartBeat)
        }
      }, 30_000) */
  });
}

/**
 * 打开 websocket
 */
export function openWebsocket() {
  state.enabled = true;
  return new Promise((resolve, reject) => {
    if (state.ws) {
      resolve(state.ws);
      return;
    }
    if (state.promises) {
      state.promises.push({ resolve, reject });
      return;
    }
    state.promises = [{ resolve, reject }];
    // 去连接
    connect(
      (ws: any) => {
        state.promises?.forEach((x) => x.resolve(ws));
        state.promises = null;
      },
      (err: any) => {
        state.promises?.forEach((x) => x.reject(err));
        state.promises = null;
      },
    );
  });
}

/**
 * 关闭 websocket
 */
export function closeWebsocket() {
  state.enabled = false;
  clearInterval(state.timer);
  if (state.ws) {
    state.ws.close();
  }
  delete state.ws;
}

/**
 * 发送消息
 * @param topic
 * @param data
 */
export function sendWebsocket(topic: string, data: any) {
  if (typeof data === 'object') {
    data = JSON.stringify(data);
  }
  return new Promise((resolve, reject) => {
    openWebsocket().then((ws: any) => {
      ws.send({
        data: `${topic}::${data}`,
        success: resolve,
        fail: reject,
      });
    });
  });
}

/**
 * vue文件使用 websocket（监听消息）
 * @param topic 消息主题
 * @param handler 消息处理事件
 */
export function useWebsocket(topic: string, handler: (data: string) => void) {
  topic = EVENT_NAME + topic;
  onUnmounted(() => {
    bus.off(topic, handler);
  });
  onMounted(() => {
    bus.on(topic, handler);
  });
  openWebsocket();
}

/**
 * 监听消息
 * @param topic 消息主题
 * @param handler 消息处理事件
 */
export function onWebsocket(topic: string, handler: (data: string) => void) {
  topic = EVENT_NAME + topic;

  bus.on(topic, handler);
  openWebsocket();

  return {
    /**
     * 取消监听
     */
    off() {
      bus.off(topic, handler);
    },
  };
}

/**
 * 取消监听消息
 * @param topic 消息主题
 * @param handler 消息处理事件
 */
export function offWebsocket(topic: string, handler: (data: string) => void) {
  topic = EVENT_NAME + topic;
  bus.off(topic, handler);
}
